package rabid;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import common.Constants;
import common.Util;

public class TermList extends Atom {
  
  private boolean moreAtomsToFind = true;
  private StringReader reader;
  private List atomList;
  private int operator;
  
  /**
   * Creates a list of all the atoms in the query
   * @param value 
   * @param operator the operator that comes directly after this term list
   */
  public TermList(String value, int operator) throws IOException {
    super(value, operator);    
    atomList = new ArrayList();
    reader = new StringReader(getAtomValue());
    initAtoms();
  }
  
  public TermList(String value) throws IOException{
    this(value, 0);
  }
  
  private void initAtoms() throws IOException {
    while(moreAtomsToFind) {
      String atomString = getNextAtom();
      Atom atom;
      if(isTermList(atomString)) {
        if(atomString.startsWith("(")) {
          //strip the parentheses
          atomString = atomString.substring(1, atomString.length()-1).trim();
        }
        atom = new TermList(atomString, operator);
      }
      else 
        atom = new AtomWord(atomString, operator);
        
      atomList.add(atom);
    }
  }
  
  private boolean isTermList(String atomString) {
    return atomString.indexOf('|') > 0 || 
           atomString.indexOf(' ') > 0 ||
           atomString.indexOf('(') > 0;
  }
  
  /**
   * Returns the next atom string in the term list and sets
   * the global operator variable to the operator for the atom
   * just read 
   * @throws IOException
   */
  private String getNextAtom() throws IOException {
    String atom = "";
    boolean termListFound = false;
    int openTermLists = 0;
    
    //get the next word or term list in the query
    int nextChar;
    for(nextChar = reader.read(); moreAtomsToFind; nextChar = reader.read()) {
      
      if(nextChar == '(') {
        openTermLists++;
        termListFound = true;
      }      
      if(nextChar == ')') {
        openTermLists--;
        termListFound = openTermLists != 0;
      }      
      if(!termListFound) {
        if(nextChar == '|') {
          operator = Constants.OP_OR;
          //skip the spaces until the start of the next atom
          while(Util.peek(reader) == ' ') reader.skip(1);
          break;
        }
        else if(nextChar == ' ') {
          if(Util.peek(reader) != '|') {
            operator = Constants.OP_AND;          
            break;
          }
        }
        else
          atom += (char)nextChar;
      }
      else
        atom += (char)nextChar;
      
      moreAtomsToFind = Util.peek(reader) != Constants.EOF;
    }    
    
    return atom;
  }
  
  public boolean evaluate(QueryWord[] mapping) {
    boolean evaluatedQuery = false;
    int operator = 0;
    
    for(int q = 0; q < atomList.size(); q++) {
      Atom atom = getAtom(atomList.get(q));
      boolean evaluatedAtom = atom.evaluate(mapping);
      
      if(operator == Constants.OP_AND)
        evaluatedQuery = evaluatedQuery && evaluatedAtom;
      else if(operator == Constants.OP_OR)
        evaluatedQuery = evaluatedQuery || evaluatedAtom;
      else
        evaluatedQuery = evaluatedAtom;
      
      operator = atom.getOperator();
    }
    return evaluatedQuery;
  }
  
  private Atom getAtom(Object obj) {
    Atom atom;
    if(obj instanceof AtomWord)
      atom = (AtomWord)obj;
    else
      atom = (TermList)obj;
    
    return atom;
  }
}
